#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
福特配置器深度分析工具 v2
使用改进的Cookie处理，重点分析点击后的HTML和数据变化
"""

import json
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException, ElementClickInterceptedException, NoSuchElementException
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service


class DeepConfiguratorAnalyzer:
    """深度配置器分析工具"""
    
    def __init__(self):
        self.driver = None
        self.wait = None
        self.analysis_results = {}
        self.html_snapshots = {}
        self.setup_driver()
    
    def setup_driver(self):
        """初始化Chrome WebDriver"""
        try:
            print("正在初始化Chrome WebDriver...")
            
            options = Options()
            options.add_argument('--no-sandbox')
            options.add_argument('--disable-dev-shm-usage')
            options.add_argument('--disable-gpu')
            options.add_argument('--window-size=1920,1080')
            
            # 设置User-Agent
            options.add_argument('--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36')
            
            # 反检测设置
            options.add_argument('--disable-blink-features=AutomationControlled')
            options.add_experimental_option("excludeSwitches", ["enable-automation"])
            options.add_experimental_option('useAutomationExtension', False)
            
            try:
                from webdriver_manager.chrome import ChromeDriverManager
                service = Service(ChromeDriverManager().install())
                self.driver = webdriver.Chrome(service=service, options=options)
            except Exception:
                self.driver = webdriver.Chrome(options=options)
            
            self.wait = WebDriverWait(self.driver, 30)
            
            # 设置反检测脚本
            self.driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})")
            
            print("WebDriver初始化成功")
            
        except Exception as e:
            print(f"WebDriver初始化失败: {e}")
            raise
    
    def handle_cookie_consent(self):
        """处理cookie同意弹窗 - 使用改进的逻辑"""
        print("检查并处理cookie同意弹窗...")
        
        try:
            # 等待一下让弹窗完全加载
            time.sleep(3)
            
            # 常见的cookie同意按钮选择器（参考scraper.py）
            cookie_selectors = [
                # Ford网站可能的选择器
                'button[data-testid="accept-all-cookies"]',
                'button[id*="accept"]',
                'button[class*="accept"]',
                'button[aria-label*="Accept"]',
                'button[aria-label*="accept"]',
                # 通用cookie同意选择器
                '.cookie-accept',
                '.accept-cookies',
                '#cookie-accept',
                '#accept-cookies',
                # 更广泛的搜索
                'button[class*="cookie"]',
                'a[class*="cookie"]',
                'div[class*="cookie"] button',
                # GDPR相关
                'button[class*="gdpr"]',
                'button[class*="consent"]',
                # 基于class名称的更精确搜索
                '[class*="CookieDisclaimer"] button',
                '[class*="styles__"] button',
                # 基于文本内容的搜索
                'button'
            ]
            
            cookie_button_found = False
            
            for selector in cookie_selectors:
                try:
                    # 查找cookie按钮
                    cookie_buttons = self.driver.find_elements(By.CSS_SELECTOR, selector)
                    
                    for button in cookie_buttons:
                        if button.is_displayed() and button.is_enabled():
                            button_text = button.text.strip().lower()
                            button_class = button.get_attribute('class') or ''
                            
                            # 检查按钮文本是否包含同意相关词汇
                            accept_keywords = ['accept', 'agree', 'ok', 'continue', 'allow', 'consent']
                            cookie_class_keywords = ['cookie', 'consent', 'gdpr', 'accept']
                            
                            text_match = any(keyword in button_text for keyword in accept_keywords)
                            class_match = any(keyword in button_class.lower() for keyword in cookie_class_keywords)
                            
                            if text_match or class_match or (selector == 'button' and 'cookie' in button_class.lower()):
                                try:
                                    print(f"找到cookie同意按钮: '{button_text}' (class: {button_class[:50]}...)")
                                    
                                    # 尝试多种点击方式
                                    try:
                                        # 滚动到按钮可见
                                        self.driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", button)
                                        time.sleep(0.5)
                                        button.click()
                                        print("✓ 已点击cookie同意按钮")
                                        cookie_button_found = True
                                        break
                                    except ElementClickInterceptedException:
                                        # 如果普通点击被拦截，使用JavaScript点击
                                        self.driver.execute_script("arguments[0].click();", button)
                                        print("✓ 已使用JavaScript点击cookie同意按钮")
                                        cookie_button_found = True
                                        break
                                except Exception as click_error:
                                    print(f"点击cookie按钮失败: {click_error}")
                                    continue
                    
                    if cookie_button_found:
                        break
                        
                except Exception as selector_error:
                    # 某个选择器失败了，继续尝试下一个
                    continue
            
            if cookie_button_found:
                print("✓ Cookie同意弹窗已处理")
                time.sleep(3)  # 等待弹窗关闭
                
                # 验证弹窗是否消失
                try:
                    cookie_dialogs = self.driver.find_elements(By.CSS_SELECTOR, '[role="dialog"][class*="Cookie"], [class*="CookieDisclaimer"]')
                    visible_dialogs = [d for d in cookie_dialogs if d.is_displayed()]
                    if not visible_dialogs:
                        print("✓ Cookie弹窗已完全消失")
                    else:
                        print(f"⚠️  仍有 {len(visible_dialogs)} 个Cookie弹窗可见")
                except Exception:
                    pass
                    
            else:
                print("ℹ️  未找到cookie同意按钮，可能页面没有弹窗或已经同意过")
                
        except Exception as e:
            print(f"处理cookie同意时出错: {e}")
            print("继续执行程序...")
    
    def capture_html_snapshot(self, step_name):
        """捕获HTML快照"""
        try:
            # 获取页面HTML
            html_content = self.driver.page_source
            
            # 获取关键元素的信息
            key_elements = {}
            
            # 导航栏状态
            try:
                nav_container = self.driver.find_element(By.CSS_SELECTOR, 'nav[data-testid="Navigation_Container"]')
                nav_items = nav_container.find_elements(By.CSS_SELECTOR, 'button, a, [role="button"]')
                key_elements['navigation'] = []
                for item in nav_items:
                    if item.is_displayed():
                        text = item.text.strip()
                        if text and len(text) < 20:
                            key_elements['navigation'].append({
                                'text': text,
                                'enabled': item.is_enabled(),
                                'aria_disabled': item.get_attribute('aria-disabled'),
                                'class': item.get_attribute('class')
                            })
            except Exception:
                key_elements['navigation'] = []
            
            # 车型元素状态
            try:
                model_elements = self.driver.find_elements(By.CSS_SELECTOR, 'div[data-cy][class*="ProductTile"]')
                key_elements['models'] = []
                for model in model_elements[:6]:  # 只记录前6个
                    data_cy = model.get_attribute('data-cy')
                    if data_cy and len(data_cy) > 2 and data_cy not in ['sticky-bar', 'disclosure-accordion']:
                        key_elements['models'].append({
                            'name': data_cy,
                            'text': model.text.strip()[:100],
                            'class': model.get_attribute('class'),
                            'displayed': model.is_displayed()
                        })
            except Exception:
                key_elements['models'] = []
            
            # 当前页面URL
            key_elements['url'] = self.driver.current_url
            key_elements['title'] = self.driver.title
            
            self.html_snapshots[step_name] = {
                'timestamp': time.time(),
                'html_length': len(html_content),
                'key_elements': key_elements
            }
            
            print(f"✓ 已捕获 {step_name} 的HTML快照 (长度: {len(html_content)} 字符)")
            
        except Exception as e:
            print(f"捕获HTML快照时出错: {e}")
    
    def analyze_deep_configuration(self, url):
        """深度分析配置器功能"""
        try:
            print(f"正在访问: {url}")
            self.driver.get(url)
            
            # 等待页面完全加载（20秒延迟以确保所有组件加载完成）
            print("等待页面完全加载（约20秒）...")
            for i in range(20):
                time.sleep(1)
                if i % 5 == 4:  # 每5秒显示一次进度
                    print(f"  加载中... {i+1}/20秒")
            
            print("页面加载完成，开始分析...")
            
            # 捕获初始状态
            self.capture_html_snapshot("initial_load")
            
            # 现在处理Cookie弹窗
            print("页面已完全加载，开始处理Cookie弹窗...")
            self.handle_cookie_consent()
            
            # 等待处理完成
            time.sleep(3)
            
            # 捕获Cookie处理后的状态
            self.capture_html_snapshot("after_cookie_consent")
            
            # 分析初始导航状态
            print("\\n=== 分析初始导航状态 ===")
            self.analyze_navigation_state("初始状态")
            
            # 尝试选择第一个车型
            print("\\n=== 尝试选择车型 ===")
            selected_model = self.select_model_with_analysis()
            
            if selected_model:
                # 捕获选择车型后的状态
                self.capture_html_snapshot("after_model_selection")
                
                # 分析选择后的导航状态
                print("\\n=== 分析车型选择后的导航状态 ===")
                self.analyze_navigation_state("车型选择后")
                
                # 尝试导航到下一步骤
                print("\\n=== 尝试导航到Drive步骤 ===")
                drive_success = self.navigate_to_step_with_analysis("Drive")
                
                if drive_success:
                    self.capture_html_snapshot("after_drive_navigation")
                    print("\\n=== 分析Drive页面 ===")
                    self.analyze_page_content("Drive")
                    
                    # 继续到Bodystyle
                    print("\\n=== 尝试导航到Bodystyle步骤 ===")
                    bodystyle_success = self.navigate_to_step_with_analysis("Bodystyle")
                    
                    if bodystyle_success:
                        self.capture_html_snapshot("after_bodystyle_navigation")
                        print("\\n=== 分析Bodystyle页面 ===")
                        self.analyze_page_content("Bodystyle")
                        
                        # 继续到Colour
                        print("\\n=== 尝试导航到Colour步骤 ===")
                        colour_success = self.navigate_to_step_with_analysis("Colour")
                        
                        if colour_success:
                            self.capture_html_snapshot("after_colour_navigation")
                            print("\\n=== 分析Colour页面 ===")
                            self.analyze_colour_page()
            
            # 分析所有快照的差异
            self.analyze_snapshots_differences()
            
        except Exception as e:
            print(f"深度分析时出错: {e}")
        finally:
            input("按Enter键关闭浏览器...")
            self.cleanup()
    
    def analyze_navigation_state(self, state_name):
        """分析导航栏状态"""
        try:
            nav_container = self.driver.find_element(By.CSS_SELECTOR, 'nav[data-testid="Navigation_Container"]')
            nav_items = nav_container.find_elements(By.CSS_SELECTOR, 'button, a, [role="button"]')
            
            print(f"    {state_name}的导航状态:")
            for item in nav_items:
                if item.is_displayed():
                    text = item.text.strip()
                    if text and len(text) < 20:
                        enabled = item.is_enabled()
                        aria_disabled = item.get_attribute('aria-disabled')
                        classes = item.get_attribute('class') or ''
                        
                        status = "可用" if (enabled and aria_disabled != 'true') else "不可用"
                        current = "← 当前" if 'cwAUaO' in classes else ""
                        
                        print(f"      {text}: {status} {current}")
                        print(f"        class: {classes[:60]}...")
                        
        except Exception as e:
            print(f"分析导航状态时出错: {e}")
    
    def select_model_with_analysis(self):
        """选择车型并分析变化"""
        try:
            models = self.driver.find_elements(By.CSS_SELECTOR, 'div[data-cy][class*="ProductTile"]')
            
            for model in models:
                data_cy = model.get_attribute('data-cy')
                if data_cy and data_cy not in ['header-selling-price', 'sticky-bar', 'disclosure-accordion'] and model.is_displayed():
                    try:
                        print(f"    尝试选择车型: {data_cy}")
                        
                        # 检查当前状态
                        classes_before = model.get_attribute('class')
                        text_before = model.text.strip()
                        
                        print(f"      选择前: class={classes_before[:50]}...")
                        print(f"      选择前: text={text_before[:50]}...")
                        
                        # 滚动到元素可见
                        self.driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", model)
                        time.sleep(1)
                        
                        # 点击选择
                        model.click()
                        print(f"    ✓ 成功点击车型: {data_cy}")
                        
                        # 等待页面更新
                        time.sleep(3)
                        
                        # 检查变化后的状态
                        try:
                            # 重新获取元素以避免stale reference
                            updated_models = self.driver.find_elements(By.CSS_SELECTOR, f'div[data-cy="{data_cy}"]')
                            if updated_models:
                                updated_model = updated_models[0]
                                classes_after = updated_model.get_attribute('class')
                                text_after = updated_model.text.strip()
                                
                                print(f"      选择后: class={classes_after[:50]}...")
                                print(f"      选择后: text={text_after[:50]}...")
                                
                                # 比较变化
                                if classes_before != classes_after:
                                    print(f"      ✓ CSS类发生变化")
                                if text_before != text_after:
                                    print(f"      ✓ 文本内容发生变化")
                        except Exception:
                            pass
                        
                        return data_cy
                        
                    except Exception as e:
                        print(f"    ✗ 选择车型 {data_cy} 失败: {e}")
                        continue
            
            print("    ✗ 无法选择任何车型")
            return None
            
        except Exception as e:
            print(f"选择车型分析时出错: {e}")
            return None
    
    def navigate_to_step_with_analysis(self, step_name):
        """导航到指定步骤并分析变化"""
        try:
            nav_container = self.driver.find_element(By.CSS_SELECTOR, 'nav[data-testid="Navigation_Container"]')
            nav_items = nav_container.find_elements(By.CSS_SELECTOR, 'button, a, [role="button"]')
            
            for item in nav_items:
                if item.is_displayed():
                    text = item.text.strip()
                    if step_name.lower() in text.lower():
                        enabled = item.is_enabled()
                        aria_disabled = item.get_attribute('aria-disabled')
                        available = enabled and aria_disabled != 'true'
                        
                        print(f"    找到{step_name}步骤: {text} - {'可用' if available else '不可用'}")
                        
                        if available:
                            try:
                                # 记录点击前的URL
                                url_before = self.driver.current_url
                                print(f"      点击前URL: {url_before}")
                                
                                # 点击导航
                                item.click()
                                print(f"    ✓ 成功点击{step_name}步骤")
                                
                                # 等待页面更新
                                time.sleep(4)
                                
                                # 记录点击后的URL
                                url_after = self.driver.current_url
                                print(f"      点击后URL: {url_after}")
                                
                                if url_before != url_after:
                                    print(f"      ✓ URL发生变化")
                                else:
                                    print(f"      ℹ️  URL未变化，可能是SPA内部路由")
                                
                                return True
                                
                            except Exception as e:
                                print(f"    ✗ 点击{step_name}步骤失败: {e}")
                        
                        return False
            
            print(f"    ✗ 未找到{step_name}步骤")
            return False
            
        except Exception as e:
            print(f"导航到{step_name}时出错: {e}")
            return False
    
    def analyze_page_content(self, step_name):
        """分析当前页面内容"""
        try:
            print(f"    分析{step_name}页面内容:")
            
            # 查找页面主要内容区域
            content_selectors = [
                '.aem-page',
                'main',
                '[class*="content"]',
                '[class*="main"]'
            ]
            
            for selector in content_selectors:
                try:
                    elements = self.driver.find_elements(By.CSS_SELECTOR, selector)
                    if elements:
                        content = elements[0]
                        text_content = content.text.strip()
                        print(f"      内容区域文本长度: {len(text_content)} 字符")
                        
                        # 显示前200个字符
                        if text_content:
                            print(f"      前200字符: {text_content[:200]}...")
                        break
                except Exception:
                    continue
            
            # 查找特定的配置选项
            self.find_configuration_options(step_name)
            
        except Exception as e:
            print(f"分析{step_name}页面内容时出错: {e}")
    
    def find_configuration_options(self, step_name):
        """查找配置选项"""
        try:
            option_selectors = [
                'button[class*="option"]',
                'div[class*="option"]',
                '[data-cy*="option"]',
                '[class*="tile"]',
                '[class*="card"]'
            ]
            
            options_found = []
            for selector in option_selectors:
                try:
                    elements = self.driver.find_elements(By.CSS_SELECTOR, selector)
                    for element in elements[:5]:  # 只检查前5个
                        if element.is_displayed():
                            text = element.text.strip()
                            data_cy = element.get_attribute('data-cy')
                            if text or data_cy:
                                options_found.append({
                                    'text': text[:30] if text else '',
                                    'data_cy': data_cy or '',
                                    'selector': selector
                                })
                except Exception:
                    continue
            
            if options_found:
                print(f"      找到 {len(options_found)} 个配置选项:")
                for option in options_found[:3]:  # 只显示前3个
                    print(f"        {option['text']} (data-cy: {option['data_cy']})")
            else:
                print(f"      未找到明显的配置选项")
                
        except Exception as e:
            print(f"查找配置选项时出错: {e}")
    
    def analyze_colour_page(self):
        """专门分析颜色页面"""
        try:
            print("    专门分析颜色配置页面:")
            
            # 查找颜色相关元素
            colour_selectors = [
                '[class*="colour"]',
                '[class*="color"]',
                '[data-testid*="colour"]',
                '[data-testid*="color"]',
                '[data-cy*="colour"]',
                '[data-cy*="color"]'
            ]
            
            colours_found = []
            for selector in colour_selectors:
                try:
                    elements = self.driver.find_elements(By.CSS_SELECTOR, selector)
                    for element in elements:
                        if element.is_displayed():
                            text = element.text.strip()
                            data_cy = element.get_attribute('data-cy')
                            classes = element.get_attribute('class')
                            if text or data_cy:
                                colours_found.append({
                                    'text': text[:50] if text else '',
                                    'data_cy': data_cy or '',
                                    'class': classes[:50] if classes else '',
                                    'tag': element.tag_name
                                })
                except Exception:
                    continue
            
            if colours_found:
                print(f"      找到 {len(colours_found)} 个颜色相关元素:")
                for colour in colours_found[:5]:  # 只显示前5个
                    print(f"        {colour['tag']}: '{colour['text']}' (class: {colour['class']})")
            else:
                print("      未找到颜色相关元素")
                
        except Exception as e:
            print(f"分析颜色页面时出错: {e}")
    
    def analyze_snapshots_differences(self):
        """分析所有快照的差异"""
        print("\\n=== 分析HTML快照差异 ===")
        
        snapshots = list(self.html_snapshots.keys())
        for i in range(len(snapshots) - 1):
            current = snapshots[i]
            next_snap = snapshots[i + 1]
            
            print(f"\\n--- {current} → {next_snap} 的变化 ---")
            
            current_data = self.html_snapshots[current]
            next_data = self.html_snapshots[next_snap]
            
            # 比较HTML长度
            html_len_diff = next_data['html_length'] - current_data['html_length']
            print(f"  HTML长度变化: {html_len_diff:+d} 字符")
            
            # 比较URL
            current_url = current_data['key_elements'].get('url', '')
            next_url = next_data['key_elements'].get('url', '')
            if current_url != next_url:
                print(f"  URL变化: {current_url} → {next_url}")
            
            # 比较导航状态
            self.compare_navigation_states(current_data, next_data)
            
            # 比较车型状态
            self.compare_model_states(current_data, next_data)
    
    def compare_navigation_states(self, before_data, after_data):
        """比较导航状态"""
        before_nav = before_data['key_elements'].get('navigation', [])
        after_nav = after_data['key_elements'].get('navigation', [])
        
        print("    导航状态变化:")
        
        # 创建导航项字典以便比较
        before_dict = {item['text']: item for item in before_nav}
        after_dict = {item['text']: item for item in after_nav}
        
        for text in set(list(before_dict.keys()) + list(after_dict.keys())):
            before_item = before_dict.get(text, {})
            after_item = after_dict.get(text, {})
            
            if before_item and after_item:
                # 检查状态变化
                before_enabled = before_item.get('enabled') and before_item.get('aria_disabled') != 'true'
                after_enabled = after_item.get('enabled') and after_item.get('aria_disabled') != 'true'
                
                if before_enabled != after_enabled:
                    status = "启用" if after_enabled else "禁用"
                    print(f"      {text}: {status}")
                
                # 检查CSS类变化
                before_class = before_item.get('class', '')
                after_class = after_item.get('class', '')
                if before_class != after_class:
                    print(f"      {text}: CSS类变化")
    
    def compare_model_states(self, before_data, after_data):
        """比较车型状态"""
        before_models = before_data['key_elements'].get('models', [])
        after_models = after_data['key_elements'].get('models', [])
        
        print("    车型状态变化:")
        
        before_dict = {model['name']: model for model in before_models}
        after_dict = {model['name']: model for model in after_models}
        
        for name in set(list(before_dict.keys()) + list(after_dict.keys())):
            before_model = before_dict.get(name, {})
            after_model = after_dict.get(name, {})
            
            if before_model and after_model:
                # 检查文本变化
                before_text = before_model.get('text', '')
                after_text = after_model.get('text', '')
                if before_text != after_text:
                    print(f"      {name}: 文本内容变化")
                
                # 检查CSS类变化
                before_class = before_model.get('class', '')
                after_class = after_model.get('class', '')
                if before_class != after_class:
                    print(f"      {name}: CSS类变化")
    
    def save_analysis_results(self):
        """保存分析结果"""
        try:
            results = {
                'html_snapshots': self.html_snapshots,
                'analysis_results': self.analysis_results
            }
            
            with open("deep_analysis_results.json", "w", encoding="utf-8") as f:
                json.dump(results, f, indent=2, ensure_ascii=False)
            print("\\n✓ 深度分析结果已保存到 deep_analysis_results.json")
        except Exception as e:
            print(f"保存分析结果时出错: {e}")
    
    def cleanup(self):
        """清理资源"""
        self.save_analysis_results()
        if self.driver:
            try:
                self.driver.quit()
                print("浏览器已关闭")
            except Exception as e:
                print(f"关闭浏览器时出错: {e}")


def main():
    """主函数"""
    url = "https://www.ford.co.uk/shop/build-your-ford/ngc2/ice2/model?catalogId=WAEGB-CGE-2022-FocusMCAGBR202450&series=ACMAA_VS-D3&paint=PN4A7&planId=c"
    
    print("福特配置器深度分析工具 v2")
    print("=" * 60)
    
    analyzer = DeepConfiguratorAnalyzer()
    analyzer.analyze_deep_configuration(url)


if __name__ == "__main__":
    main()